# dependent_case.py
import ast
import json
from typing import Text, Dict, Union, List, Any, Optional  # 新增Any和Optional导入
from jsonpath import jsonpath
from utils.requests_tool.request_control import RequestControl
from utils.mysql_tool.mysql_control import SetUpMySQL
from utils.read_files_tools.regular_control import regular, cache_regular
from utils.other_tools.jsonpath_date_replace import jsonpath_replace
from utils.logging_tool.log_control import WARNING
from utils.other_tools.models import DependentType
from utils.other_tools.models import TestCase, DependentCaseData, DependentData
from utils.other_tools.exceptions import ValueNotFoundError
from utils.cache_process.cache_control import CacheHandler
from utils import config


class DependentCase:
    """ 处理依赖相关的业务 """

    def __init__(self, dependent_yaml_case: TestCase):
        self.__yaml_case = dependent_yaml_case

    @staticmethod
    def convert_value_type(value: Any, value_type: Optional[str]) -> Any:
        """根据value_type转换数据类型"""
        if value_type:
            type_mapping = {
                "str": str,
                "int": int,
                "float": float,
                "bool": lambda x: x.lower() == "true" if isinstance(x, str) else bool(x),
                "list": ast.literal_eval,
                "dict": ast.literal_eval
            }
            try:
                return type_mapping[value_type](value)
            except (ValueError, SyntaxError) as e:
                raise ValueError(f"类型转换失败: {value} 转换为 {value_type} 时出错: {str(e)}")
        return value

    @classmethod
    def get_cache(cls, case_id: Text) -> Dict:
        _case_data = CacheHandler.get_cache(case_id)
        return _case_data

    @classmethod
    def jsonpath_data(cls, obj: Dict, expr: Text) -> list:
        _jsonpath_data = jsonpath(obj, expr)
        if _jsonpath_data is False:
            raise ValueNotFoundError(
                f"jsonpath提取失败！\n 提取的数据: {obj} \n jsonpath规则: {expr}"
            )
        return _jsonpath_data

    @classmethod
    def set_cache_value(cls, dependent_data: "DependentData") -> Optional[Text]:
        try:
            return dependent_data.set_cache
        except KeyError:
            return None

    @classmethod
    def replace_key(cls, dependent_data: "DependentData") -> Optional[Text]:
        try:
            return dependent_data.replace_key
        except KeyError:
            return None

    def url_replace(self, replace_key: Text, jsonpath_dates: Dict, jsonpath_data: list) -> None:
        replace_value = str(jsonpath_data[0])
        if "$url_param" in replace_key:
            _url = self.__yaml_case.url.replace(replace_key, replace_value)
            jsonpath_dates['$.url'] = _url
        else:
            jsonpath_dates[replace_key] = jsonpath_data[0]

    def _dependent_type_for_sql(self, setup_sql: List, dependence_case_data: "DependentCaseData",
                                jsonpath_dates: Dict) -> None:
        if setup_sql is not None and config.mysql_db.switch:
            setup_sql = ast.literal_eval(cache_regular(str(setup_sql)))
            sql_data = SetUpMySQL().setup_sql_data(sql=setup_sql)
            for i in dependence_case_data.dependent_data:
                jsonpath_data = self.jsonpath_data(sql_data, i.jsonpath)
                converted_value = self.convert_value_type(jsonpath_data[0], i.value_type)

                if (set_value := self.set_cache_value(i)) is not None:
                    CacheHandler.update_cache(set_value, converted_value)

                if (replace_key := self.replace_key(i)) is not None:
                    jsonpath_dates[replace_key] = converted_value
                    self.url_replace(replace_key, jsonpath_dates, [converted_value])

    def dependent_handler(self,
                          _jsonpath: Text,
                          set_value: Optional[Text],
                          replace_key: Optional[Text],  # 修改参数类型提示
                          jsonpath_dates: Dict,
                          data: Dict,
                          dependent_type: int,
                          value_type: Optional[Text] = None) -> None:
        jsonpath_data = self.jsonpath_data(data, _jsonpath)
        converted_data = [self.convert_value_type(x, value_type) for x in jsonpath_data]

        if set_value is not None:
            cache_value = converted_data if len(converted_data) > 1 else converted_data[0]
            CacheHandler.update_cache(set_value, cache_value)

        if replace_key is not None and converted_data:
            target_value = converted_data[0]
            if dependent_type == 0:
                jsonpath_dates[replace_key] = target_value
            self.url_replace(replace_key, jsonpath_dates, [target_value])

    def is_dependent(self) -> Union[Dict, bool]:
        if self.__yaml_case.dependence_case is True:
            jsonpath_dates = {}
            try:
                for case_data in self.__yaml_case.dependence_case_data:
                    if case_data.case_id == 'self':
                        self._dependent_type_for_sql(self.__yaml_case.setup_sql, case_data, jsonpath_dates)
                    else:
                        case_response = self._process_dependent_case(case_data)
                        self._handle_dependent_data(case_data, case_response, jsonpath_dates)
                return jsonpath_dates
            except (KeyError, TypeError) as e:
                raise ValueNotFoundError(str(e)) from e
        return False

    def _process_dependent_case(self, case_data: DependentCaseData) -> Any:
        re_data = regular(str(self.get_cache(case_data.case_id)))
        return RequestControl(ast.literal_eval(cache_regular(str(re_data)))).http_request()

    def _handle_dependent_data(self,
                               case_data: DependentCaseData,
                               response: Any,  # 明确标注response类型
                               jsonpath_dates: Dict) -> None:
        if case_data.dependent_data:
            for dep_data in case_data.dependent_data:
                source_data = self._get_source_data(dep_data, response)
                self.dependent_handler(
                    _jsonpath=dep_data.jsonpath,
                    set_value=dep_data.set_cache,
                    replace_key=dep_data.replace_key,
                    jsonpath_dates=jsonpath_dates,
                    data=source_data,
                    dependent_type=0 if dep_data.dependent_type == DependentType.RESPONSE.value else 1,
                    value_type=dep_data.value_type
                )

    def _get_source_data(self, dep_data: DependentData, response: Any) -> Dict:  # 添加返回值类型
        if dep_data.dependent_type == DependentType.RESPONSE.value:
            return json.loads(response.response_data)
        elif dep_data.dependent_type == DependentType.REQUEST.value:
            return response.body
        else:
            raise ValueError(f"不支持的依赖类型: {dep_data.dependent_type}")

    def get_dependent_data(self) -> None:
        if (dependent_data := self.is_dependent()) not in (False, None):
            for key, value in dependent_data.items():
                # 修改点1：使用实例属性代替局部变量
                exec_code = jsonpath_replace(
                    change_data=key.split("."),
                    key_name='self._DependentCase__yaml_case'  # 直接引用私有变量
                ) + f' = {repr(value)}'

                # 修改点2：传递当前实例的本地变量到exec环境
                exec(exec_code, {'self': self})
